﻿using System;
using System.IO;

using Microsoft.Xna.Framework.Graphics;

using SceneEngine;

using DialogResult = System.Windows.Forms.DialogResult;

namespace SceneEditor
{
    public partial class Editor
    {
        void perlinToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            EngineGlobals.Scene.HeightMap.RandomizeHeight(GenerationType.PerlinNoise, true);
        }

        void perlinToolStripMenuItem_Click(object sender, EventArgs e)
        {
            EngineGlobals.Scene.HeightMap.RandomizeHeight(GenerationType.PerlinNoise, false);
        }

        void randomToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            EngineGlobals.Scene.HeightMap.RandomizeHeight(GenerationType.Random, true);
        }

        void randomToolStripMenuItem_Click(object sender, EventArgs e)
        {
            EngineGlobals.Scene.HeightMap.RandomizeHeight(GenerationType.Random, false);
        }

        void smoothHeightMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (NumericEntryForm entryForm = new NumericEntryForm())
            {
                entryForm.lblText.Text = "Number of Passes";
                entryForm.tbValue.Minimum = 1;
                entryForm.tbValue.Maximum = 100;

                if (entryForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    for (int i = 0; i < (int)entryForm.tbValue.Value; i++)
                    {
                        EngineGlobals.Scene.HeightMap.SmoothHeightMap();
                    }
                }
            }
        }

        void generateColourMapToolStripMenuItem_Click(object sender, EventArgs e)
        {
            EngineGlobals.Scene.HeightMap.GenerateColorMap();
        }

        void tbCursorStrength_ValueChanged(object sender, EventArgs e)
        {
            EngineGlobals.Scene.HeightMap.CursorStrength = editor.tbCursorStrength.Value;
        }

        void tbCursorSize_ValueChanged(object sender, EventArgs e)
        {
            EngineGlobals.Scene.HeightMap.CursorSize = editor.tbCursorSize.Value;
        }

        void tbMaxHeight_ValueChanged(object sender, EventArgs e)
        {
            EngineGlobals.Scene.HeightMap.UpdateMaxHeight((float)editor.tbMaxHeight.Value);

            terrainChangesMade = true;
            changesMade = true;

            scene.HeightMap.UpdateHeightTexture();
            scene.HeightMap.UpdateColorTexture(true);
        }

        void tbTerrainTexture4_ValueChanged(object sender, EventArgs e)
        {
            scene.HeightMap.SetMaterialScale(4, (float)editor.tbTerrainTexture4.Value);
        }
        void tbTerrainTexture3_ValueChanged(object sender, EventArgs e)
        {
            scene.HeightMap.SetMaterialScale(3, (float)editor.tbTerrainTexture3.Value);
        }
        void tbTerrainTexture2_ValueChanged(object sender, EventArgs e)
        {
            scene.HeightMap.SetMaterialScale(2, (float)editor.tbTerrainTexture2.Value);
        }
        void tbTerrainTexture1_ValueChanged(object sender, EventArgs e)
        {
            scene.HeightMap.SetMaterialScale(1, (float)editor.tbTerrainTexture1.Value);
        }

        private void ChooseTerrainMaterial(int channel, System.Windows.Forms.PictureBox pictureBox)
        {
            if (Directory.Exists(Path.Combine(EditorGlobals.ContentPath, "Terrain")) == false)
            {
                Directory.CreateDirectory(Path.Combine(EditorGlobals.ContentPath, "Terrain"));
            }

            using (System.Windows.Forms.OpenFileDialog openDialog =
                new System.Windows.Forms.OpenFileDialog())
            {
                openDialog.Filter = "Png Files .png|*.png";

                if (openDialog.ShowDialog() == DialogResult.OK)
                {
                    string filePath = openDialog.FileName;
                    string fileName = Path.GetFileName(filePath);

                    string copyPath = Path.Combine(EditorGlobals.ContentPath, "Terrain", fileName);

                    if (filePath != copyPath)
                    {
                        if (File.Exists(copyPath) == true)
                        {
                            DialogResult result = MessageBoxHelper.ShowFileExists();

                            if (result == DialogResult.Yes)
                            {
                                try
                                {
                                    File.Delete(copyPath);
                                    File.Copy(filePath, copyPath);
                                }
                                catch
                                {
                                    MessageBoxHelper.ShowErrorOccured();
                                }
                            }
                            else
                            {
                                return;
                            }
                        }
                        else
                        {
                            File.Copy(filePath, copyPath);
                        }
                    }

                    using (FileStream stream = new FileStream(copyPath, FileMode.Open))
                    {
                        Texture2D texture = Texture2D.FromStream(GraphicsDevice, stream);

                        string relativePath = "Terrain\\" + Path.GetFileName(copyPath);

                        if (EditorGlobals.ContainsContentItem(relativePath) == false)
                        {
                            EditorGlobals.AddContentItem(Path.GetFileName(copyPath), relativePath, null, null);
                        }

                        scene.HeightMap.SetTerrainMaterial(channel, texture, "Terrain\\" + fileName);

                        pictureBox.Image = EditorGlobals.Texture2DToImage(texture, 64);
                        pictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
                    }
                }
            }
        }

        void pbTerrainTexture1_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            ChooseTerrainMaterial(1, editor.pbTerrainTexture1);
        }
        void pbTerrainTexture2_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            ChooseTerrainMaterial(2, editor.pbTerrainTexture2);
        }
        void pbTerrainTexture3_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            ChooseTerrainMaterial(3, editor.pbTerrainTexture3);
        }
        void pbTerrainTexture4_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            ChooseTerrainMaterial(4, editor.pbTerrainTexture4);
        }

        private void LoadColorMap(object sender, EventArgs e)
        {
            if (scene.HeightMap == null)
            {
                return;
            }

            using (System.Windows.Forms.OpenFileDialog openDialog =
                new System.Windows.Forms.OpenFileDialog())
            {
                openDialog.Filter = "Png Files .png|*.png";

                if (openDialog.ShowDialog() == DialogResult.OK)
                {
                    if (File.Exists(openDialog.FileName) == false)
                    {
                        MessageBoxHelper.ShowFileNotFound();
                        return;
                    }

                    Texture2D colorMap = null;

                    using (FileStream fileStream = new FileStream(openDialog.FileName, FileMode.Open))
                    {
                        colorMap = Texture2D.FromStream(EngineGlobals.GraphicsDevice, fileStream);
                    }

                    if (colorMap == null)
                    {
                        return;
                    }

                    if (colorMap.Width != colorMap.Height)
                    {
                        MessageBoxHelper.ShowHeightmapWrongSize();
                        return;
                    }

                    if (((colorMap.Width != 0) && ((colorMap.Width & (colorMap.Width - 1)) == 0)) == false ||
                        ((colorMap.Height != 0) && ((colorMap.Height & (colorMap.Height - 1)) == 0)) == false)
                    {
                        MessageBoxHelper.ShowHeightmapWrongSize();
                        return;
                    }

                    if (colorMapChangesMade && MessageBoxHelper.ShowSaveColorMapChanges() == DialogResult.Yes)
                    {
                        SaveColorMap(null, null);
                    }

                    string fileName = Path.GetFileNameWithoutExtension(openDialog.FileName);
                    string relativeName = Path.Combine("Terrain", fileName);
                    string relativePath = string.Concat(relativeName, ".png");

                    if (EditorGlobals.ContainsContentItem(relativePath) &&
                        MessageBoxHelper.ShowFileExists() != DialogResult.Yes)
                    {
                        return;
                    }

                    string copyPath = Path.Combine(EditorGlobals.ContentPath, relativePath);

                    if (Directory.Exists(Path.GetDirectoryName(copyPath)) == false)
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(copyPath));
                    }

                    else if (File.Exists(copyPath) && openDialog.FileName != copyPath)
                    {
                        try
                        {
                            File.Delete(copyPath);
                        }
                        catch
                        {
                            MessageBoxHelper.ShowErrorOccured();
                            return;
                        }
                    }

                    if (openDialog.FileName != copyPath)
                    {
                        File.Copy(openDialog.FileName, copyPath);
                    }

                    if (EditorGlobals.ContainsContentItem(relativePath) == false)
                    {
                        EditorGlobals.AddContentItem(fileName, relativePath, null, null);
                    }

                    colorMapChangesMade = false;

                    scene.ColorMapPath = relativeName;
                    editor.lblColorMap.Text = scene.ColorMapPath;

                    scene.HeightMap.LoadColormap(colorMap);
                }
            }
        }
        private void SaveColorMap(object sender, EventArgs e)
        {
            string relativeName = scene.ColorMapPath;

            string relativePath = string.IsNullOrEmpty(relativeName) ?
                                  string.Empty : relativeName + ".png";

            string copyPath = Path.Combine(EditorGlobals.ContentPath, relativePath);

            if (string.IsNullOrEmpty(scene.ColorMapPath))
            {
                TextEntryForm entryForm = new TextEntryForm();
                entryForm.Text = "Choose a name for your color map.";
                entryForm.lblText.Text = "Name";
                entryForm.tbText.Text = "ColorMap1";

                if (entryForm.ShowDialog() == DialogResult.OK)
                {
                    relativeName = Path.Combine("Terrain", entryForm.tbText.Text);
                    relativePath = string.Concat(relativeName, ".png");

                    copyPath = Path.Combine(EditorGlobals.ContentPath, relativePath);

                    if (File.Exists(copyPath) && MessageBoxHelper.ShowFileExists() != DialogResult.Yes)
                    {
                        return;
                    }

                    if (EditorGlobals.ContainsContentItem(relativePath) == false)
                    {
                        EditorGlobals.AddContentItem(entryForm.tbText.Text, relativePath, null, null);
                    }

                    scene.ColorMapPath = relativeName;
                    editor.lblColorMap.Text = scene.ColorMapPath;
                }
                else
                {
                    return;
                }
            }

            try
            {
                using (FileStream fileStream = new FileStream(copyPath, FileMode.Create))
                {
                    scene.HeightMap.ColorMap.SaveAsPng(fileStream, scene.HeightMap.ColorMap.Width,
                                                                   scene.HeightMap.ColorMap.Height);

                    colorMapChangesMade = false;
                }
            }
            catch
            {
                MessageBoxHelper.ShowErrorOccured();
            }
        }

        private void LoadHeightMap(object sender, EventArgs e)
        {
            using (System.Windows.Forms.OpenFileDialog openDialog =
                new System.Windows.Forms.OpenFileDialog())
            {
                openDialog.Filter = "Png Files .png|*.png";

                if (openDialog.ShowDialog() == DialogResult.OK)
                {
                    if (File.Exists(openDialog.FileName) == false)
                    {
                        MessageBoxHelper.ShowFileNotFound();
                        return;
                    }

                    Texture2D heightMap = null;

                    using (FileStream fileStream = new FileStream(openDialog.FileName, FileMode.Open))
                    {
                        heightMap = Texture2D.FromStream(EngineGlobals.GraphicsDevice, fileStream);
                    }

                    if (heightMap == null)
                    {
                        return;
                    }

                    if (heightMap.Width != heightMap.Height ||
                        ((heightMap.Width != 0) && ((heightMap.Width & (heightMap.Width - 1)) == 0)) == false ||
                        ((heightMap.Height != 0) && ((heightMap.Height & (heightMap.Height - 1)) == 0)) == false)
                    {
                        MessageBoxHelper.ShowHeightmapWrongSize();
                        return;
                    }

                    string fileName = Path.GetFileNameWithoutExtension(openDialog.FileName);
                    string relativeName = Path.Combine("Terrain", fileName);
                    string relativePath = string.Concat(relativeName, ".png");

                    if (EditorGlobals.ContainsContentItem(relativePath) &&
                        MessageBoxHelper.ShowFileExists() != DialogResult.Yes)
                    {
                        return;
                    }

                    if (terrainChangesMade && MessageBoxHelper.ShowSaveTerrainChanges() == DialogResult.Yes)
                    {
                        SaveHeightmap(null, null);
                    }

                    string copyPath = Path.Combine(EditorGlobals.ContentPath, relativePath);

                    if (Directory.Exists(Path.GetDirectoryName(copyPath)) == false)
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(copyPath));
                    }

                    else if (File.Exists(copyPath) && openDialog.FileName != copyPath)
                    {
                        try
                        {
                            File.Delete(copyPath);
                        }
                        catch
                        {
                            MessageBoxHelper.ShowErrorOccured();
                            return;
                        }
                    }

                    if (openDialog.FileName != copyPath)
                    {
                        File.Copy(openDialog.FileName, copyPath);
                    }

                    if (EditorGlobals.ContainsContentItem(relativePath) == false)
                    {
                        EditorGlobals.AddContentItem(fileName, relativePath, null, null);
                    }

                    if (scene.HeightMap == null)
                    {
                        scene.HeightMap = new HeightMap(10.0f);
                        scene.HeightMap.CreateNewHeightMap(MapSize.Medium);
                    }

                    scene.HeightMapPath = relativeName;
                    editor.lblHeightMap.Text = scene.HeightMapPath;

                    scene.HeightMap.LoadHeightMap(heightMap);
                }
            }
        }
        private void SaveHeightmap(object sender, EventArgs e)
        {
            string relativeName = scene.HeightMapPath;

            string relativePath = string.IsNullOrEmpty(relativeName) ?
                                  string.Empty : relativeName + ".png";

            string copyPath = Path.Combine(EditorGlobals.ContentPath, relativePath);

            if (string.IsNullOrEmpty(scene.HeightMapPath))
            {
                TextEntryForm entryForm = new TextEntryForm();
                entryForm.Text = "Choose a name for your height map.";
                entryForm.lblText.Text = "Name";
                entryForm.tbText.Text = "HeightMap1";

                if (entryForm.ShowDialog() == DialogResult.OK)
                {
                    relativeName = Path.Combine("Terrain", entryForm.tbText.Text);
                    relativePath = string.Concat(relativeName, ".png");

                    copyPath = Path.Combine(EditorGlobals.ContentPath, relativePath);

                    if (File.Exists(copyPath) && MessageBoxHelper.ShowFileExists() != DialogResult.Yes)
                    {
                        return;
                    }

                    if (EditorGlobals.ContainsContentItem(relativePath) == false)
                    {
                        EditorGlobals.AddContentItem(entryForm.tbText.Text, relativePath, null, null);
                    }

                    scene.HeightMapPath = relativeName;
                    editor.lblHeightMap.Text = scene.HeightMapPath;
                }
                else
                {
                    return;
                }
            }

            try
            {
                using (FileStream fileStream = new FileStream(Path.Combine(
                    EditorGlobals.ContentPath, relativePath), FileMode.Create))
                {
                    scene.HeightMap.Texture.SaveAsPng(fileStream, scene.HeightMap.Texture.Width,
                                                                  scene.HeightMap.Texture.Height);

                    terrainChangesMade = false;
                }
            }
            catch
            {
                MessageBoxHelper.ShowErrorOccured();
            }
        }

        private void btnClearHeightMap_Click(object sender, EventArgs e)
        {
            scene.HeightMap = null;

            scene.HeightMapPath = string.Empty;
            scene.ColorMapPath = string.Empty;

            editor.lblHeightMap.Text = string.Empty;
            editor.lblColorMap.Text = string.Empty;

            editor.pbHeightMap.Image = global::SceneEditor.Resources._checked;
            editor.pbColorMap.Image = global::SceneEditor.Resources._checked;

            editor.pnlTerrain.Enabled = false;

            editor.generateColourMapToolStripMenuItem.Enabled = false;
            editor.generateNoiseToolStripMenuItem.Enabled = false;
            editor.smoothHeightMapToolStripMenuItem.Enabled = false;

            changesMade = true;
        }

        private void btnCreateLargeTerrain_Click(object sender, EventArgs e)
        {
            CreateTerrain(MapSize.Large);
        }
        private void btnCreateMediumTerrain_Click(object sender, EventArgs e)
        {
            CreateTerrain(MapSize.Medium);
        }
        private void btnCreateSmallTerrain_Click(object sender, EventArgs e)
        {
            CreateTerrain(MapSize.Small);
        }

        private void CreateTerrain(MapSize size)
        {
            using (NumericEntryForm entryForm = new NumericEntryForm())
            {
                entryForm.lblText.Text = "Cell Size";
                entryForm.tbValue.Minimum = editor.tbCellSize.Minimum;
                entryForm.tbValue.Maximum = editor.tbCellSize.Maximum;
                entryForm.tbValue.Value = editor.tbCellSize.Minimum;

                if (entryForm.ShowDialog() == DialogResult.OK)
                {
                    scene.HeightMap = new HeightMap((float)entryForm.tbValue.Value);
                    scene.HeightMap.HeightMapChanged += new EventHandler(HeightMap_TextureChanged);
                    scene.HeightMap.ColorMapChanged += new EventHandler(HeightMap_ColorMapChanged);

                    scene.HeightMap.CreateNewHeightMap(size);

                    scene.HeightMapPath = string.Empty;

                    // Form
                    UpdateTerrainTab(true);
                }
            }
        }
        private void UpdateTerrainTab(bool enable)
        {
            editor.generateColourMapToolStripMenuItem.Enabled = enable;
            editor.generateNoiseToolStripMenuItem.Enabled = enable;
            editor.smoothHeightMapToolStripMenuItem.Enabled = enable;

            editor.pnlTerrain.Enabled = enable;

            editor.pbHeightMap.Image = enable ? EditorGlobals.Texture2DToImage(
                EngineGlobals.Scene.HeightMap.Texture, 64) : null;

            editor.pbColorMap.Image = enable ? EditorGlobals.Texture2DToImage(
                EngineGlobals.Scene.HeightMap.ColorMap, 64) : null;

            editor.pbTerrainTexture1.Image = enable ? EditorGlobals.Texture2DToImage(
                EngineGlobals.Scene.HeightMap.Materials[1].Texture, 64) : null;

            editor.pbTerrainTexture2.Image = enable ? EditorGlobals.Texture2DToImage(
                EngineGlobals.Scene.HeightMap.Materials[2].Texture, 64) : null;

            editor.pbTerrainTexture3.Image = enable ? EditorGlobals.Texture2DToImage(
                EngineGlobals.Scene.HeightMap.Materials[3].Texture, 64) : null;

            editor.pbTerrainTexture4.Image = enable ? EditorGlobals.Texture2DToImage(
                EngineGlobals.Scene.HeightMap.Materials[4].Texture, 64) : null;

            editor.tbTerrainTexture1.Value = enable ? (decimal)scene.HeightMap.Materials[1].Scale : 10.0M;
            editor.tbTerrainTexture2.Value = enable ? (decimal)scene.HeightMap.Materials[2].Scale : 10.0M;
            editor.tbTerrainTexture3.Value = enable ? (decimal)scene.HeightMap.Materials[3].Scale : 10.0M;
            editor.tbTerrainTexture4.Value = enable ? (decimal)scene.HeightMap.Materials[4].Scale : 10.0M;

            editor.lblHeightMap.Text = enable ? scene.HeightMapPath : string.Empty;
            editor.lblColorMap.Text = enable ? scene.ColorMapPath : string.Empty;

            editor.tbCellSize.Value = (decimal)(enable ? scene.HeightMap.CellSize : 10.0f);
        }

        private void toolControl_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (editor.toolControl.SelectedTab.Text == "Terrain")
            {
                gizmo.Transforms.Clear();
            }
        }

        private void HeightMap_TextureChanged(object sender, EventArgs e)
        {
            editor.pbHeightMap.Image = EditorGlobals.Texture2DToImage(
                EngineGlobals.Scene.HeightMap.Texture, 64);

            terrainChangesMade = true;
        }
        private void HeightMap_ColorMapChanged(object sender, EventArgs e)
        {
            editor.pbColorMap.Image = EditorGlobals.Texture2DToImage(
                EngineGlobals.Scene.HeightMap.ColorMap, 64);

            colorMapChangesMade = true;
        }
    }
}
